optional chain & nullish coalescing operator

可选链式调用与空值合并运算符

正常返回的数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const interfaceList = [
{
id: 1104,
name: 'onlinemq1:tp_mdm_user:broker-dev:1',
data: {
avgRt: 75.48,
avgRtComparePrev: '-19.28%',
hitCount: 42,
},
},
{
id: 1102,
name: 'ymmoa:oabbsService_1.0.0:selectValidChildrenBlocks()',
data: {
avgRt: 13.34,
avgRtComparePrev: '39.92%',
hitCount: 116,
},
},
];

然后我们就这样写了

1
2
3
4
5
6
7
8
9
10
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>请求量:{inter.data.hitCount}</div>
<div>平均响应时间:{inter.data.avgRt}</div>
<div>平均RT环比昨日:{inter.data.avgRtComparePrev}</div>
</div>
));
}

异常非正常返回的数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const interfaceList = [
{
// 情况 1
id: 1101,
name: 'onlinemq1:tp_mdm_user:broker-dev:1',
data: {
avgRt: 0,
avgRtComparePrev: '0.00%',
hitCount: 0,
},
},
{
// 情况 2
id: 1102,
name: 'ymmoa:oabbsService_1.0.0:selectValidChildrenBlocks()',
data: {
avgRt: null,
avgRtComparePrev: '',
hitCount: null,
},
},
{
// 情况 3
id: 1102,
name: '/cat/r/p',
data: {},
},
{
// 情况 4
id: 1102,
name: '/cat/r/p',
data: null,
},
{
// 情况 5
id: 1102,
name: '/cat/r/p',
},
];

const interfaceList = null; // 情况6

问题开始暴露

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 情况 1 暂时没问题
// 情况 2 空白
// 情况 3 空白
// 情况 4 ❌ Uncaught TypeError: Cannot read property 'XXX' of null
// 情况 5 ❌ Uncaught TypeError: Cannot read property 'XXX' of undefined
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>请求量:{inter.data.hitCount}</div>
<div>平均响应时间:{inter.data.avgRt}</div>
<div>平均RT环比昨日:{inter.data.avgRtComparePrev}</div>
</div>
));
}

展示’-‘,表示暂无数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 情况 1 ❌ 数据为 0 也成了暂无数据
// 情况 2 暂时没问题
// 情况 3 暂时没问题
// 情况 4 ❌ Uncaught TypeError: Cannot read property 'XXX' of null
// 情况 5 ❌ Uncaught TypeError: Cannot read property 'XXX' of undefined
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>请求量:{inter.data.hitCount || '-'}</div>
<div>平均响应时间:{inter.data.avgRt || '-'}</div>
<div>平均RT环比昨日:{inter.data.avgRtComparePrev || '-'}</div>
</div>
));
}

解决情况 1、4、5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 情况 1 暂时没问题
// 情况 2 ❌ avgRtComparePrev 是 '' 表示没数据
// 情况 3 暂时没问题
// 情况 4 暂时没问题
// 情况 5 暂时没问题
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{inter.data !== null &&
inter.data !== undefined &&
inter.data.hitCount !== null &&
inter.data.hitCount !== undefined
? inter.data.hitCount
: '-'}
</div>
<div>
平均响应时间:
{inter.data !== null && inter.data !== undefined && inter.data.avgRt !== null && inter.data.avgRt !== undefined
? inter.data.avgRt
: '-'}
</div>
<div>
平均RT环比昨日:
{inter.data !== null &&
inter.data !== undefined &&
inter.data.avgRtComparePrev !== null &&
inter.data.avgRtComparePrev !== undefined
? inter.data.avgRtComparePrev
: '-'}
</div>
</div>
));
}

优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 情况 1 没问题
// 情况 2 没问题
// 情况 3 没问题
// 情况 4 没问题
// 情况 5 没问题
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{inter.data !== null &&
inter.data !== undefined &&
inter.data.hitCount !== null &&
inter.data.hitCount !== undefined
? inter.data.hitCount
: '-'}
</div>
<div>
平均响应时间:
{inter.data !== null && inter.data !== undefined && inter.data.avgRt !== null && inter.data.avgRt !== undefined
? inter.data.avgRt
: '-'}
</div>
<div>
平均RT环比昨日:
{inter.data !== null && inter.data !== undefined && inter.data.avgRtComparePrev
? inter.data.avgRtComparePrev
: '-'}
</div>
</div>
));
}

再优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{!_.isNil(inter.data) && !_.isNil(inter.data.hitCount) ? inter.data.hitCount : '-'}
</div>
<div>
平均响应时间:
{!_.isNil(inter.data) && !_.isNil(inter.data.avgRt) ? inter.data.avgRt : '-'}
</div>
<div>
平均RT环比昨日:
{!_.isNil(inter.data) && inter.data.avgRtComparePrev ? inter.data.avgRtComparePrev : '-'}
</div>
</div>
));
}

既然都用了 lodash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
interfaceList.map(inter => {
// 不推荐使用 get 的第三个参数设置默认值,因为只有在 undefined 的时候才会设置,null 被认为是有值的
const hitCount = _.get(inter, 'data.hitCount');
const avgRt = _.get(inter, 'data.avgRt');
const avgRtComparePrev = _.get(inter, 'data.avgRtComparePrev');
return (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{!_.isNil(hitCount) ? hitCount : '-'}
</div>
<div>
平均响应时间:
{!_.isNil(avgRt) ? avgRt : '-'}
</div>
<div>
平均RT环比昨日:
{avgRtComparePrev || '-'}
</div>
</div>
);
});
}

用 optional chain 替换掉 _.get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 情况 1 暂时没问题
// 情况 2 暂时没问题
// 情况 3 暂时没问题
// 情况 4 暂时没问题
// 情况 5 暂时没问题
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{!_.isNil(inter.data?.hitCount) ? inter.data?.hitCount : '-'}
</div>
<div>
平均响应时间:
{!_.isNil(inter.data?.avgRt) ? inter.data?.avgRt : '-'}
</div>
<div>
平均RT环比昨日:
{inter.data?.avgRtComparePrev || '-'}
</div>
</div>
));
}

用 nullish coalescing operator 替换掉 _.isNill

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 情况 1 暂时没问题
// 情况 2 暂时没问题
// 情况 3 暂时没问题
// 情况 4 暂时没问题
// 情况 5 暂时没问题
{
interfaceList.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{inter.data?.hitCount ?? '-'}
</div>
<div>
平均响应时间:
{inter.data?.avgRt ?? '-'}
</div>
<div>
平均RT环比昨日:
{inter.data?.avgRtComparePrev || '-'}
</div>
</div>
));
}

情况 6 来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
interfaceList?.map(inter => (
<div key={inter.id}>
<div>接口名:{inter.name}</div>
<div>
请求量:
{inter.data?.hitCount ?? '-'}
</div>
<div>
平均响应时间:
{inter.data?.avgRt ?? '-'}
</div>
<div>
平均RT环比昨日:
{inter.data?.avgRtComparePrev || '-'}
</div>
</div>
));
}

这么爽!我能用了吗?

  • Finished Proposals
  • TypeScript 3.7 supports Optional Chaining & Nullish Coalescing
  • Babel 7.8.0 supports Optional Chaining & Nullish Coalescing
  • @babel/proposal-optional-chaining,
  • @babel/proposal-nullish-coalescing-operator